package com.xinke.module.system.service.oauth2;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.xinke.component.common.enums.CommonStatusEnum;
import com.xinke.component.common.util.string.StrUtils;
import com.xinke.module.system.redis.RedisKeyConstants;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import com.xinke.module.system.model.vo.oauth2.*;
import com.xinke.module.system.model.entity.oauth2.OAuth2ClientDO;
import com.xinke.component.common.pojo.PageResult;
import com.xinke.component.common.util.object.BeanUtils;

import com.xinke.module.system.mapper.oauth2.OAuth2ClientMapper;

import static com.xinke.component.common.exception.util.ServiceExceptionUtil.exception;
import static com.xinke.module.system.enums.ErrorCodeConstants.*;

/**
 * OAuth2 客户端 Service 实现类
 *
 * @author yzx
 */
@Service
@Validated
public class OAuth2ClientServiceImpl implements OAuth2ClientService {

    @Resource
    private OAuth2ClientMapper oAuth2ClientMapper;

    @Override
    public Long createOAuth2Client(OAuth2ClientSaveReqVO createReqVO) {
        // 插入
        OAuth2ClientDO oAuth2Client = BeanUtils.toBean(createReqVO, OAuth2ClientDO.class);
        oAuth2ClientMapper.insert(oAuth2Client);
        // 返回
        return oAuth2Client.getClientId();
    }

    @Override
    public void updateOAuth2Client(OAuth2ClientSaveReqVO updateReqVO) {
        // 校验存在
        validateOAuth2ClientExists(updateReqVO.getClientId());
        // 更新
        OAuth2ClientDO updateObj = BeanUtils.toBean(updateReqVO, OAuth2ClientDO.class);
        oAuth2ClientMapper.updateById(updateObj);
    }

    @Override
    public void deleteOAuth2Client(Long clientId) {
        // 校验存在
        validateOAuth2ClientExists(clientId);
        // 删除
        oAuth2ClientMapper.deleteById(clientId);
    }

    private void validateOAuth2ClientExists(Long clientId) {
        if (oAuth2ClientMapper.selectById(clientId) == null) {
            throw exception(null);
        }
    }

    @Override
    public OAuth2ClientDO getOAuth2Client(Long clientId) {
        return oAuth2ClientMapper.selectById(clientId);
    }

    @Override
    public PageResult<OAuth2ClientDO> getOAuth2ClientPage(OAuth2ClientPageReqVO pageReqVO) {
        return oAuth2ClientMapper.selectPage(pageReqVO);
    }

    @Override
    @Cacheable(cacheNames = RedisKeyConstants.OAUTH_CLIENT, key = "#clientNo",
            unless = "#result == null")
    public OAuth2ClientDO getOAuth2ClientFromCache(String clientNo) {
        return oAuth2ClientMapper.selectByClientNo(clientNo);
    }
    @Override
    public OAuth2ClientDO validOAuthClientFromCache(String clientNo, String clientSecret, String authorizedGrantType, Collection<String> scopes, String redirectUri) {
        // 校验客户端存在、且开启
        OAuth2ClientDO client = getSelf().getOAuth2ClientFromCache(clientNo);
        if (client == null) {
            throw exception(OAUTH2_CLIENT_NOT_EXISTS);
        }
        if (CommonStatusEnum.isDisable(client.getClientStatus())) {
            throw exception(OAUTH2_CLIENT_DISABLE);
        }

        // 校验客户端密钥
        if (StrUtil.isNotEmpty(clientSecret) && ObjectUtil.notEqual(client.getClientSecret(), clientSecret)) {
            throw exception(OAUTH2_CLIENT_CLIENT_SECRET_ERROR);
        }
        // 校验授权方式
        if (StrUtil.isNotEmpty(authorizedGrantType) && !CollUtil.contains(client.getAuthorizedGrantTypes(), authorizedGrantType)) {
            throw exception(OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS);
        }
        // 校验授权范围
        if (CollUtil.isNotEmpty(scopes) && !CollUtil.containsAll(client.getAuthScope(), scopes)) {
            throw exception(OAUTH2_CLIENT_SCOPE_OVER);
        }
        // 校验回调地址
        if (StrUtil.isNotEmpty(redirectUri) && !StrUtils.startWithAny(redirectUri, client.getRedirectUri())) {
            throw exception(OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH, redirectUri);
        }
        return client;
    }
    /**
     * 获得自身的代理对象，解决 AOP 生效问题
     *
     * @return 自己
     */
    private OAuth2ClientServiceImpl getSelf() {
        return SpringUtil.getBean(getClass());
    }

}